package com.mybatis;


import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * 两级缓存：
 * 一级缓存：（本地缓存）： 与数据库同一次会话期间查询到的数据会放在本地缓存中。以后如果需要获取相同的数据，直接从缓存中拿，没必要再去查数据库
 *     一级缓存失效的情况（没有使用到当前一级缓存的情况，效果就是，还需要再向数据库发出查询）：
 *      1、不同会话（session不同)
 *      2、sqlsession相同，查询条件不同
 *      3、sqlsession相同，两次查询之间执行了增删改
 *      4、sqlsession相同，手动清除了一级缓存（缓存清空）
 * 二级缓存：（全局缓存）:基于namespace级别的缓存，一个namespace对应一个二级缓存
 *      工作机制：
 *      1、一个会话，查询一个数据，这个数据就会被放在当前会话的一级缓存中
 *      2、如果会话关闭；一级缓存中的数据会被保存到二级缓存中；新的会话查询信息，就可以参照二级缓存中
 *      3、sqlSession === EmployeeMapper ==>Employee
 *                         DepartmentMapper ===>Department
 *            不同namespace查出的数据会放在自己对应的缓存中（map)
 *            效果：数据会从二级缓存中获取
 *              查出的数据都会默认放在一级缓存中。
 *              只有会话提交或者关闭后，一级缓存中的数据才会转移到二级缓存中
 *      使用：
 *          1）开启全局二级缓存配置 setting cacheEnabled=true
 *          2)去mapper.xml中配置使用二级缓存：
 *          3)我们的POJO需要实现序列化接口
 *和缓存有关的设置/属性：
 *      1）cacheEnable = true   关闭的缓存级别:二级缓存；与一级缓存无关
 *      2）<select ... useCache="true"></select>   ---->针对二级缓存
 *      3）每个增删改标签的 flushCache = "true"
 *              增删改执行完后就会清空缓存：
 *              测试：flushCache="true"，一级二级缓存被清空
 *              查询标签默认 flushCache="false"，如果改为true,每次查询之后都会清空缓存；缓存是没有被使用的；
 *      4) sqlSession.clearCache(); 清楚当前session的一级缓存
 *      5) localCacheScope:本地缓存作用域：（一级缓存session)：当前会话的所有数据保存会话中
 *                  Statement:可以禁用一级缓存
 *
 */
public class MyBatisCacheTest {

	public static void main(String[] args) throws IOException {
		/*一级缓存*/
		//firstCache();
		/*二级缓存骚操作*/
		secondCache();
	}

	private static void secondCache() throws IOException {
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		SqlSession sqlSession = sessionFactory.openSession();
		EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
		Map<String, Object> map = mapper.selectMap(1);
		System.out.println(map);
		sqlSession.close();

		/*第一个session close的时候，由于开启了二级缓存，所以会在一级缓存关闭之时，把缓存存入二级缓存中，第二个会话查询相同的数据，就会命中缓存。*/
		SqlSession sqlSession1 = sessionFactory.openSession();
		EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
		Map<String, Object> map2 = mapper1.selectMap(1);
		System.out.println(map2);
		sqlSession1.close();
	}

	private static void firstCache() throws IOException {
		String config = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(config);
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		SqlSession session = sessionFactory.openSession();
		EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
		SqlSession session2 = sessionFactory.openSession();
		EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);

		/*session不同*/
//		queryCache(mapper,mapper2,1,1);
		//查询条件不同
		//queryCache(mapper,mapper2,1,2);
		//中间添加增删改
//		queryCacheCRUD(mapper,mapper,1,1);

		/*queryCache(mapper,mapper2,1,1);
		session.clearCache();
		queryCache(mapper,mapper2,1,1);*/

		session.close();
	}

	private static void queryCacheCRUD(EmployeeMapper mapper, EmployeeMapper mapper2, int id1, int id2) {
		Map<String, Object> maps = mapper.selectMap(id1);
		System.out.println(maps);
		Employee employee = new Employee();
		employee.setId(1);
		employee.setGender("1");
		mapper2.updateEmp(employee);
		Map<String, Object> maps2 = mapper2.selectMap(id2);
		System.out.println(maps2);
		System.out.println(maps==maps2);
	}

	private static void queryCache(EmployeeMapper mapper, EmployeeMapper mapper2,Integer id1,Integer id2) {
		Map<String, Object> maps = mapper.selectMap(id1);
		System.out.println(maps);
		Map<String, Object> maps2 = mapper2.selectMap(id2);
		System.out.println(maps2);
		System.out.println(maps==maps2);
	}


}
